package user

import (
	"context"
	"git.mycaigou.com/gfyx/common/tenant_db"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/common/constants"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/common/utils"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/base/role"
	"git.myscrm.cn/golang/stark/v4"
	"github.com/google/uuid"
	"gorm.io/gorm"
	"time"
)

type userRepository struct {
	tenant_db.TenantDB
}

// NewUserRepository 构造函数
func NewUserRepository() UserRepositoryIface {
	return &userRepository{}
}

// GetUserByMobile 手机号获取用户信息
func (r *userRepository) GetUserByMobile(ctx context.Context, mobile string) (*GfyxUserPo, error) {
	userInfo := &GfyxUserPo{}
	err := r.GetTenantDB(ctx).Table(userInfo.TableName()).
		Where("is_deleted = ?", constants.IsDeletedFalse).
		Where("mobile = ?", mobile).
		First(userInfo).
		Error
	if err != nil && err != gorm.ErrRecordNotFound {
		stark.Logger.Errorf(ctx, "repository-method:GetUserByMobile, err:%v", err)
		return nil, err
	}

	return userInfo, nil
}

// GetUserByAccountOrMobile 通过账号或手机号获取用户信息
func (r *userRepository) GetUserByAccountOrMobile(ctx context.Context, account string) (*GfyxUserPo, error) {
	userInfo := &GfyxUserPo{}
	err := r.GetTenantDB(ctx).Table(userInfo.TableName()).
		Where("is_deleted = ?", constants.IsDeletedFalse).
		Where("mobile = ? or account = ? ", account, account).
		First(userInfo).
		Error
	if err != nil && err != gorm.ErrRecordNotFound {
		stark.Logger.Errorf(ctx, "repository-method:GetUserByAccountOrMobile, err:%v", err)
		return nil, err
	}

	return userInfo, nil
}

// GetUserByCondition 自定义获取用户信息
func (r *userRepository) GetUserByCondition(ctx context.Context, condition map[string]interface{}) (*GfyxUserPo, error) {
	userInfo := &GfyxUserPo{}
	err := r.GetTenantDB(ctx).Table(userInfo.TableName()).
		Where("is_deleted = ?", constants.IsDeletedFalse).
		Where(condition).
		First(userInfo).
		Error
	if err != nil && err != gorm.ErrRecordNotFound {
		stark.Logger.Errorf(ctx, "repository-method:GetUserByCondition, err:%v", err)
		return nil, err
	}

	return userInfo, nil
}

// SaveUser 保存记录
func (r *userRepository) SaveUser(ctx context.Context, data *GfyxUserPo) (int64, error) {
	result := r.GetTenantDB(ctx).Table(GfyxUserPo{}.TableName()).Save(data)
	if result.Error != nil {
		stark.Logger.Errorf(ctx, "SaveUser save data : %+v, error: %+v", data, result.Error)
		return 0, result.Error
	}

	// 建模表myuser,保存用户信息
	updateData := map[string]interface{}{
		"username":    data.Name,
		"mobilephone": data.Mobile,
		"email":       data.Email,
		"position":    data.Position,
	}
	if data.Password != "" && data.Salt != "" {
		updateData["password"] = data.Password
		updateData["salt"] = data.Salt
	}
	err := r.GetTenantDB(ctx).Table(MyUserPo{}.TableName()).
		Where("userguid = ?", data.Uid).
		Limit(1).
		Updates(updateData).Error
	if err != nil {
		stark.Logger.Errorf(ctx, "SaveUser save data : %+v, error: %+v", updateData, err)
		return 0, err
	}

	return result.RowsAffected, nil
}

// UserList 用户列表
func (r *userRepository) UserList(ctx context.Context, userIds []int64, status int32, keyword string, page *utils.PageInfo) ([]*GfyxUserPo, *utils.PageInfo, error) {
	list := make([]*GfyxUserPo, 0)
	db := r.GetTenantDB(ctx).Table(GfyxUserPo{}.TableName()).Where("is_deleted = ?", constants.IsDeletedFalse).Where("id in (?)", userIds)
	if keyword != "" {
		keyword = "%" + keyword + "%"
		db = db.Where("name like ? or mobile like ?", keyword, keyword)
	}

	if status != 0 {
		db = db.Where("status = ?", status)
	}

	var total int64
	err := db.Count(&total).Error
	if err != nil {
		return nil, nil, err
	}
	page.Total = total
	if page != nil && page.Page > 0 && page.PageSize > 0 {
		db = db.Offset((page.Page - 1) * page.PageSize).Limit(page.PageSize)
	}
	err = db.Find(&list).Error
	return list, page, err
}

// UserDetailByUserId 获取用户详情根据手机号
func (r *userRepository) UserDetailByUserId(ctx context.Context, userId int64) (*GfyxUserPo, error) {
	var userObj = &GfyxUserPo{}
	err := r.GetTenantDB(ctx).
		Where("is_deleted = ? and id = ?", constants.IsDeletedFalse, userId).
		First(userObj).Error
	if err != nil && err != gorm.ErrRecordNotFound {
		return nil, err
	}
	return userObj, nil
}

// UserDetailByAccount 获取用户详情根据账号
func (r *userRepository) UserDetailByAccount(ctx context.Context, account string) (*GfyxUserPo, error) {
	var userObj = &GfyxUserPo{}
	err := r.GetTenantDB(ctx).
		Where("is_deleted = ? and account = ?", constants.IsDeletedFalse, account).
		First(userObj).Error
	if err != nil && err != gorm.ErrRecordNotFound {
		return nil, err
	}
	return userObj, nil
}

// SaveUserAll 新增加或修改数用户数据
func (r *userRepository) SaveUserAll(ctx context.Context, userOjb *GfyxUserPo, roleIds []int64, orgIds []int64, orgGuids []string) (int64, error) {
	db := r.GetTenantDB(ctx)
	db = db.Begin()
	userId, err := r.saveUserAll(ctx, db, userOjb, roleIds, orgIds, orgGuids)
	if err != nil {
		db.Rollback()
		return 0, err
	}
	db.Commit()

	return userId, nil
}

func (r *userRepository) saveUserAll(ctx context.Context, db *gorm.DB, userObj *GfyxUserPo, roleIds []int64, orgIds []int64, orgGuids []string) (int64, error) {
	var isAddUser bool
	// 1. 保存用户信息
	userId := userObj.Id
	if userObj.Id == 0 {
		isAddUser = true
		err := db.Save(userObj).Error
		if err != nil {
			return 0, err
		}
		userId = userObj.Id
	} else {
		updateData := map[string]interface{}{
			"name":     userObj.Name,
			"mobile":   userObj.Mobile,
			"email":    userObj.Email,
			"position": userObj.Position,
		}
		if userObj.Password != "" && userObj.Salt != "" {
			updateData["password"] = userObj.Password
			updateData["salt"] = userObj.Salt
		}
		err := db.Table(GfyxUserPo{}.TableName()).
			Where("id = ?", userObj.Id).
			Limit(1).
			Updates(updateData).Error
		if err != nil {
			return 0, err
		}
	}

	// 2. 删除角色/组织关系数据
	err := db.Table(GfyxUserOrganizationRelationPo{}.TableName()).Where("user_id = ?", userId).Updates(map[string]interface{}{
		"is_deleted":  constants.IsDeletedTrue,
		"modified_on": time.Now(),
		"modified_by": "",
	}).Error
	if err != nil {
		return 0, err
	}
	err = db.Table(GfyUserRoleRelationPo{}.TableName()).Where("user_id = ?", userId).Updates(map[string]interface{}{
		"is_deleted":  constants.IsDeletedTrue,
		"modified_on": time.Now(),
		"modified_by": "",
	}).Error
	if err != nil {
		return 0, err
	}

	// 3. 保存用户组织关系
	for _, orgId := range orgIds {
		userOrgObj := &GfyxUserOrganizationRelationPo{
			UserId:         userId,
			OrganizationId: orgId,
			//IsResponsible:  1,
			CreatedOn:  time.Now(),
			CreatedBy:  "",
			ModifiedOn: time.Now(),
			ModifiedBy: "",
		}
		err := db.Save(userOrgObj).Error
		if err != nil {
			return 0, err
		}
	}

	// 4. 保存用户角色关系
	for _, roleId := range roleIds {
		userRoleObj := &GfyUserRoleRelationPo{
			UserId:     userId,
			RoleId:     roleId,
			CreatedOn:  time.Now(),
			CreatedBy:  "",
			ModifiedOn: time.Now(),
			ModifiedBy: "",
		}
		err := db.Save(userRoleObj).Error
		if err != nil {
			return 0, err
		}
	}

	// 5. 建模表——保存用户信息
	if isAddUser {
		myUser := map[string]interface{}{
			"buguid":       orgGuids[0],
			"userguid":     userObj.Uid,
			"usercode":     userObj.Mobile,
			"username":     userObj.Name,
			"mobilephone":  userObj.Mobile,
			"email":        userObj.Email,
			"position":     userObj.Position,
			"salt":         userObj.Salt,
			"password":     userObj.Password,
			"isdisabeld":   0,
			"createdtime":  time.Now(),
			"modifiedtime": time.Now(),
			"userkind":     0,
		}
		if err := db.Table(MyUserPo{}.TableName()).Create(myUser).Error; err != nil {
			return 0, err
		}

		// 建模表-保存用户和角色的关系
		var (
			orgGuid string
		)
		if orgGuids != nil && len(orgGuids) > 0 {
			orgGuid = orgGuids[0]
		}
		// 读取（建模表的）角色表的StandardRoleName=供方saas的角色ID，如果获取不到，则不处理
		mystandardrolePo := role.MystandardrolePo{}
		err = db.Where("StandardRoleName = ?", "供方saas").First(&mystandardrolePo).Error
		if err != nil && err != gorm.ErrRecordNotFound {
			return 0, err
		}
		if mystandardrolePo.MyStandardRoleId != "" {
			myuser2RolePo := role.Myuser2RolePo{
				MyUser2RoleId:  uuid.New().String(),
				CreatedName:    "系统管理员",
				ModifiedName:   "系统管理员",
				CreatedTime:    time.Now(),
				ModifiedTime:   time.Now(),
				CreatedGUID:    "4230bc6e-69e6-46a9-a39e-b929a06a84e8",
				ModifiedGUID:   "4230bc6e-69e6-46a9-a39e-b929a06a84e8",
				UserID:         userObj.Uid,
				OrganizationID: orgGuid,
				RoleID:         mystandardrolePo.MyStandardRoleId,
				RefType:        1,
			}
			if err := db.Create(&myuser2RolePo).Error; err != nil {
				return 0, err
			}
		}
	} else {
		updateData := map[string]interface{}{
			"username":    userObj.Name,
			"mobilephone": userObj.Mobile,
			"email":       userObj.Email,
			"position":    userObj.Position,
		}
		if userObj.Password != "" && userObj.Salt != "" {
			updateData["password"] = userObj.Password
			updateData["salt"] = userObj.Salt
		}
		err = db.Table(MyUserPo{}.TableName()).
			Where("userguid = ?", userObj.Uid).
			Limit(1).
			Updates(updateData).Error
		if err != nil {
			return 0, err
		}
	}

	// 6. 建模表——保存用户组织关系
	myuserbusinessunitmappingPo := MyuserbusinessunitmappingPo{}
	if err := db.Where("userid = ?", userObj.Uid).Delete(&myuserbusinessunitmappingPo).Error; err != nil {
		return 0, nil
	}
	for _, orgGuid := range orgGuids {
		myuserbusinessunitmapping := map[string]interface{}{
			"myUserBusinessUnitMappingId": uuid.New().String(),
			"VersionNumber":               time.Now(),
			"UserId":                      userObj.Uid,
			"BUGUID":                      orgGuid,
			"createdtime":                 time.Now(),
			"modifiedtime":                time.Now(),
		}
		if err := db.Table(MyuserbusinessunitmappingPo{}.TableName()).Create(myuserbusinessunitmapping).Error; err != nil {
			return 0, err
		}
	}

	// 7. 经确认，用户角色不需要不同给建模

	return userId, nil
}

// UserDelete 删除账号
func (r *userRepository) UserDelete(ctx context.Context, userId int64, userGuid string) (int64, error) {
	db := r.GetTenantDB(ctx)
	db = db.Begin()
	err := db.Table(GfyxUserPo{}.TableName()).
		Where("id = ?", userId).
		Limit(1).
		Updates(map[string]interface{}{
			"is_deleted":  constants.IsDeletedTrue,
			"modified_on": time.Now(),
			"modified_by": "",
		}).Error
	if err != nil {
		db.Rollback()
		return userId, err
	}

	err = db.Table(GfyxUserOrganizationRelationPo{}.TableName()).
		Where("user_id = ?", userId).
		Updates(map[string]interface{}{
			"is_deleted":  constants.IsDeletedTrue,
			"modified_on": time.Now(),
			"modified_by": "",
		}).Error

	if err != nil {
		db.Rollback()
		return 0, err
	}

	err = db.Table(GfyUserRoleRelationPo{}.TableName()).
		Where("user_id = ?", userId).
		Updates(map[string]interface{}{
			"is_deleted":  constants.IsDeletedTrue,
			"modified_on": time.Now(),
			"modified_by": "",
		}).Error
	if err != nil {
		db.Rollback()
		return 0, err
	}

	// 建模表——删除用户
	myUserPo := MyUserPo{}
	myuserbusinessunitmappingPo := MyuserbusinessunitmappingPo{}
	// 删除用户表
	if err := db.Where("userguid = ?", userGuid).Delete(&myUserPo).Error; err != nil {
		db.Rollback()
		return 0, err
	}
	// 删除用户组织表
	if err := db.Where("userid = ?", userGuid).Delete(myuserbusinessunitmappingPo).Error; err != nil {
		db.Rollback()
		return 0, err
	}

	db.Commit()

	return userId, nil
}

// UserForbid 禁用用户
func (r *userRepository) UserForbid(ctx context.Context, userId int64, userGuid string, status int32) (int64, error) {
	db := r.GetTenantDB(ctx)
	db = db.Begin()
	err := db.Table(GfyxUserPo{}.TableName()).
		Where("id = ?", userId).
		Limit(1).
		Updates(map[string]interface{}{
			"status":      status, //禁用
			"modified_on": time.Now(),
			"modified_by": "",
		}).Error
	if err != nil {
		db.Rollback()
		return userId, err
	}

	// 建模表——禁用用户
	err = db.Table(MyUserPo{}.TableName()).
		Where("userguid = ?", userGuid).
		Limit(1).
		Updates(map[string]interface{}{
			"isdisabeld":   status - 1,
			"modifiedtime": time.Now(),
		}).Error
	if err != nil {
		db.Rollback()
		return userId, err
	}

	db.Commit()
	return userId, nil
}

func (r *userRepository) QueryUserList(ctx context.Context, condition map[string]interface{}, pageInfo *utils.PageInfo, orderBy string) (int64, []*GfyxUserPo, error) {
	db := r.GetTenantDB(ctx).Table(GfyxUserPo{}.TableName())

	// todo 判断可等双写结束后删除掉
	if val, ok := condition["user_guids"]; ok {
		db = db.Where("uid in (?)", val)
		delete(condition, "user_guids")
	}

	if val, ok := condition["user_ids"]; ok {
		db = db.Where("id in (?)", val)
		delete(condition, "user_ids")
	}

	if val, ok := condition["user_names"]; ok {
		db = db.Where("name in (?)", val)
		delete(condition, "user_names")
	}

	db = db.Where(condition)
	var count int64
	var queryList []*GfyxUserPo
	err := db.Count(&count).Error
	if err != nil {
		return 0, nil, err
	}

	if pageInfo != nil && pageInfo.Page > 0 && pageInfo.PageSize > 0 {
		db = db.Offset((pageInfo.Page - 1) * pageInfo.PageSize).Limit(pageInfo.PageSize)
	}
	if orderBy != "" {
		db.Order(orderBy)
	} else {
		db.Order("id")
	}
	err = db.Find(&queryList).Error
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return 0, nil, nil
		}
		return 0, nil, err
	}
	return count, queryList, nil
}

func (r *userRepository) UpdateUserByCondition(ctx context.Context, condition, updates map[string]interface{}) error {
	db := r.GetTenantDB(ctx).Table(GfyxUserPo{}.TableName())
	if userIds, ok := condition["ids"]; ok {
		db.Where("id in (?)", userIds)
		delete(condition, "ids")
	}
	if userGuids, ok := condition["guids"]; ok {
		db.Where("uid in (?)", userGuids)
		delete(condition, "guids")
	}
	return db.Where(condition).Updates(updates).Error
}

func (r *userRepository) GetUserCount(ctx context.Context, condition map[string]interface{}) (int64, error) {
	var total int64
	db := r.GetTenantDB(ctx).Table(GfyxUserPo{}.TableName()).Where(condition)
	err := db.Count(&total).Error
	if err != nil && err != gorm.ErrRecordNotFound {
		return 0, db.Error
	}
	if err == gorm.ErrRecordNotFound {
		return 0, nil
	}
	return total, nil
}

func (r *userRepository) GetMyUserInfoByUserGuid(ctx context.Context, userGuid string) (*MyUserPo, error) {
	myUserPo := MyUserPo{}
	if err := r.GetTenantDB(ctx).Where("UserGUID = ?", userGuid).First(&myUserPo).Error; err != nil && err != gorm.ErrRecordNotFound {
		return nil, err
	}
	return &myUserPo, nil

}
